#define _GNU_SOURCE
#include "app_device.h"
#include <fcntl.h>
#include "app_common.h"
#include "app_message.h"
#include "app_mqtt.h"
#include "app_pool.h"
#include "log/log.h"
#include <stdlib.h>
#include <unistd.h>

#define BUFFER_SIZE 1024
#define POOL_SIZE 5
#define WRITE_INTERVAL_MS 200 // 两次写入间隔时间，单位毫秒

static Device *device = NULL;

Device *app_device_init(char *filename) // 单例模式
{
    if (device)
    {
        return device;
    }

    // 申请内存
    device = malloc(sizeof(Device));
    // 初始化内部属性
    device->filename = filename;
    device->fd = open(filename, O_RDWR);
    device->up_buffer = app_buffer_init(BUFFER_SIZE);
    device->down_buffer = app_buffer_init(BUFFER_SIZE);
    device->is_running = 0;
    device->last_write_time = 0;
    device->pre_write = NULL;
    device->post_read = NULL;

    // 初始线程池
    if (app_pool_init(POOL_SIZE) != 0)
    {
        close(device->fd);
        app_buffer_free(device->up_buffer);
        app_buffer_free(device->down_buffer);
        free(device);
        return NULL;
    }

    // 初始化mqtt
    if (app_mqtt_init() != 0)
    {
        close(device->fd);
        app_buffer_free(device->up_buffer);
        app_buffer_free(device->down_buffer);
        app_pool_destroy();
        free(device);
        return NULL;
    }

    return device;
}

// 发送消息的任务函数
static int send_task_fun(void *arg)
{
    // 从上行缓冲区读取一个消息数据
    char data_buf[128];
    int len = app_buffer_read(device->up_buffer, data_buf, sizeof(data_buf));
    // 将字符数组消息数据转换为json消息
    char *json = app_message_charsToJson(data_buf, len);
    // 发送json消息给远程
    int result = app_mqtt_send(json);
    if (result != 0)
    {
        log_error("消息发送失败");
        free(json);
        return -1;
    }
    log_debug("消息发送成功： %s", json);
    free(json);

    return 0;
}

// 不断读取串口文件数据的线程
static void *read_thread_fun(void *arg)
{
    while (device->is_running)
    {
        char data_buf[128];
        ssize_t len = read(device->fd, data_buf, sizeof(data_buf));
        if (len > 0)
        { // 读取到了数据（蓝牙格式）
            // 将蓝牙格式数据转换为字符数组消息
            if (device->post_read)
            {
                len = device->post_read(data_buf, len);
            }
        }

        if (len > 0)
        {
            // 将字符数组消息保存到上行缓冲区
            app_buffer_write(device->up_buffer, data_buf, len);
            // 添加一个发送消息的任务，让线程池的分线程去处理
            app_pool_addTask(send_task_fun, NULL);
        }
    }

    return NULL;
}

// 写数据到串口文件的任务函数  在线程池中的某个分线程执行
static int write_task_fun(void *arg)
{
    Device *dev = (Device *)arg;

    // 从下行缓冲区读取一个消息数据
    char data_buf[128];
    int len = app_buffer_read(dev->down_buffer, data_buf, sizeof(data_buf));

    // 将字符数组消息数据转换为蓝牙格式数据
    if (len > 0 && dev->pre_write)
    {
        len = dev->pre_write(data_buf, len);
        if (len > 0)
        {
            // 保证两次写入的间隔时间不能小于200ms
           // long distance = app_common_getCurrentTime() - dev->last_write_time;
           long distance = 0;
            while ((distance = app_common_getCurrentTime() - dev->last_write_time) < WRITE_INTERVAL_MS)
            {
                usleep((WRITE_INTERVAL_MS - distance) * 1000);
            }

            // 记录写数据的时间
            dev->last_write_time = app_common_getCurrentTime();
            
            // 写数据到串口文件
            ssize_t write_len = write(dev->fd, data_buf, len);
            if (write_len != len)
            {
                log_error("写数据到串口文件失败");
                return -1;
            }
            log_debug("写数据到串口文件成功");

            

            return 0;
        }
    }

    return -1;
}

// 接收远程消息的回调函数
static int receive_msg_callback(char *json)
{
    // 将json消息转换为字符数组消息
    char data_buf[128];
    int len = app_message_jsonToChars(json, data_buf, sizeof(data_buf));
    // 将字符数组消息保存到下行缓冲区
    app_buffer_write(device->down_buffer, data_buf, len);
    // 将保存数据到串口的任务交给线程池去处理
    app_pool_addTask(write_task_fun, device);

    return 0;
}

int app_device_start()
{
    if (device->is_running)
    {
        log_debug("读线程已经启动运行了");
        return 0;
    }
    device->is_running = 1;
    // 创建读线程
    pthread_create(&device->read_thread, NULL, read_thread_fun, NULL);

    // 注册接收远程消息的回调函数
    app_mqtt_registerRecvCallback(receive_msg_callback);

    return 0;
}

void app_device_stop()
{
    // 关闭文件
    close(device->fd);

    // 释放2个缓冲区
    app_buffer_free(device->up_buffer);
    app_buffer_free(device->down_buffer);

    // 停止读线程
    device->is_running = 0;
    pthread_cancel(device->read_thread);

    // 释放device
    free(device);

    // 释放线程池
    app_pool_destroy();

    // 释放mqtt
    app_mqtt_close();
}
